﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Samurai.Wakizashi.Workflow.Fluent
{
    [TestClass]
    public class ExtensionsTests
    {
        [TestMethod]
        public void WhenProvidedAnAction_RegistersActionWithWorkflowInstance()
        {
            var workflow = new Mock<ISequentialWorkflow<IWorkflowContext>>();
            var blankAction = new Action(() => { });

            Extensions.Do(workflow.Object, blankAction).Done();

            workflow.Verify(w => w.RegisterStep(blankAction, ThreadType.Current, null, null));
        }

        [TestMethod]
        public void WhenProvidedAnActionAndPredicate_RegistersActionAndPredicateWithWorkflowInstance()
        {
            var workflow = new Mock<ISequentialWorkflow<IWorkflowContext>>();
            var blankAction = new Action(() => { });
            var predicate = new Predicate<IWorkflowContext>(c => true);

            Extensions.Do(workflow.Object, blankAction)
                .If(predicate)
                .Done();

            workflow.Verify(w => w.RegisterStep(blankAction, ThreadType.Current, predicate, null));
        }

        [TestMethod]
        public void WhenProvidedAStepName_ForwardsNameToWorkflowInstance()
        {
            var workflow = new Mock<ISequentialWorkflow<IWorkflowContext>>();
            var blankAction = new Action(() => { });
            var predicate = new Predicate<IWorkflowContext>(c => true);

            Extensions.Do(workflow.Object, blankAction)
                .Named("TestName")
                .If(predicate)
                .Done();

            workflow.Verify(w => w.RegisterStep(blankAction, ThreadType.Current, predicate, "TestName"));
        }

        [TestMethod]
        public void WhenProvidedAThreadType_ForwardsThreadTypeToWorkflowInstance()
        {
            var workflow = new Mock<ISequentialWorkflow<IWorkflowContext>>();
            var blankAction = new Action(() => { });
            var predicate = new Predicate<IWorkflowContext>(c => true);

            Extensions.Do(workflow.Object, blankAction)
                .OnThread(ThreadType.Task)
                .Named("TestName")
                .If(predicate)
                .Done();

            workflow.Verify(w => w.RegisterStep(blankAction, ThreadType.Task, predicate, "TestName"));
        }

        internal class TestWorkflow : ISequentialWorkflow<TestWorkflowContext>
        {
            #region Implementation of IWorkflow<TestWorkflowContext>

#pragma warning disable 67
            public event EventHandler<WorkflowCompletedEventArgs<TestWorkflowContext>> WorkflowCompleted;
            public event EventHandler<WorkflowCompletedEventArgs<TestWorkflowContext>> WorkflowFailed;
#pragma warning restore 67


            /// <summary>
            /// Gets or sets the context which to pass along the workflow as it executes.
            /// </summary>
            /// <value>The context.</value>
            public TestWorkflowContext Context { get; set; }

            /// <summary>
            /// Gets or sets a value indicating whether or not to restart the workflow after the last step completes.
            /// </summary>
            /// <value><c>true</c> if [loop workflow]; otherwise, <c>false</c>.</value>
            public bool LoopWorkflow { get; set; }

            /// <summary>
            /// Gets the number of actions registered in the workflow.
            /// </summary>
            /// <value>The count.</value>
            public int Count { get; private set; }

            /// <summary>
            /// Clears all registered actions from the workflow.
            /// </summary>
            public void Clear()
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Starts the workflow by executing the first step.
            /// </summary>
            public void Start()
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Places a request to stop the workflow instance at the most convenient point.
            /// </summary>
            public void RequestStop()
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Called when the final step in the workflow has completed.
            /// </summary>
            public void OnCompleted(Action<WorkflowCompletedEventArgs<TestWorkflowContext>> action)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Calledwhen a step in the workflow fails.
            /// </summary>
            public void OnFailed(Action<WorkflowCompletedEventArgs<TestWorkflowContext>> action)
            {
                throw new NotImplementedException();
            }

            #endregion

            #region Implementation of ISequentialWorkflow<TestWorkflowContext>

            /// <summary>
            /// Gets the steps that make up the current workflow instance.
            /// </summary>
            /// <value>The workflow steps.</value>
            public IEnumerable<IWorkflowStep<TestWorkflowContext>> WorkflowSteps { get; private set; }

            /// <summary>
            /// Suspends the current workflow for the specified amount of time. Once this time 
            /// has elapsed, the workflow will continue to the next step.
            /// </summary>
            /// <param name="amountOfTimeToSuspend">The amount of time to suspend.</param>
            public void Suspend(TimeSpan amountOfTimeToSuspend)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Configures the specified config action.
            /// </summary>
            /// <param name="configAction">The config action.</param>
            public void Configure(Action<ISequentialWorkflow<TestWorkflowContext>> configAction)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided step with the workflow.
            /// </summary>
            /// <param name="step">The step.</param>
            public void RegisterStep(IWorkflowStep<TestWorkflowContext> step)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided step with the workflow. Will execute if provided predicate evaluates to true at execution time. Will
            /// execute on the current thread.
            /// </summary>
            /// <param name="step">The step.</param>
            /// <param name="canExecute">Execution condition.</param>
            public void RegisterStep(IWorkflowStep<TestWorkflowContext> step, Predicate<TestWorkflowContext> canExecute)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided step with the workflow on the specified thread in which to execute.
            /// </summary>
            /// <param name="step">The step.</param>
            /// <param name="thread">The thread.</param>
            public void RegisterStep(IWorkflowStep<TestWorkflowContext> step, ThreadType thread)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided step with the workflow on the specified thread in which to execute. Will 
            /// execute if provided predicate evaluates to true at execution time.
            /// </summary>
            /// <param name="step">The step.</param>
            /// <param name="thread">The thread.</param>
            /// <param name="canExecute">Execution condition.</param>
            public void RegisterStep(IWorkflowStep<TestWorkflowContext> step, ThreadType thread, Predicate<TestWorkflowContext> canExecute)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided action as a step in the workflow to be executed on the current thread.
            /// </summary>
            /// <param name="step">The step.</param>
            public void RegisterStep(Action step)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided action as a step in the workflow on the specified thread in which to execute.
            /// </summary>
            /// <param name="step">The step.</param>
            /// <param name="thread">The thread.</param>
            public void RegisterStep(Action step, ThreadType thread)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided action as a step in the workflow on the specified thread in which to execute. Will 
            /// only execute the step if execution condition evaluates to 'true' when the step is next in the workflow.
            /// </summary>
            /// <param name="step">The step.</param>
            /// <param name="canExecute">Execution condition.</param>
            public void RegisterStep(Action step, Predicate<TestWorkflowContext> canExecute)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided action as a step in the workflow on the specified thread in which to execute. Will
            /// only execute the step if execution condition evaluates to 'true' when the step is next in the workflow.
            /// </summary>
            /// <param name="step">The step.</param>
            /// <param name="thread">The thread.</param>
            /// <param name="canExecute">Execution condition.</param>
            /// <param name="stepName">Name of the step.</param>
            public void RegisterStep(Action step, ThreadType thread, Predicate<TestWorkflowContext> canExecute, string stepName)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided action as a step in the workflow to be executed on the current thread.
            /// </summary>
            /// <param name="step">The step.</param>
            public void RegisterStep(Action<TestWorkflowContext> step)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided action as a step in the workflow on the specified thread in which to execute.
            /// </summary>
            /// <param name="step">The step.</param>
            /// <param name="thread">The thread.</param>
            public void RegisterStep(Action<TestWorkflowContext> step, ThreadType thread)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided action as a step in the workflow on the specified thread in which to execute. Will 
            /// only execute the step if execution condition evaluates to 'true' when the step is next in the workflow.
            /// </summary>
            /// <param name="step">The step.</param>
            /// <param name="canExecute">Execution condition.</param>
            public void RegisterStep(Action<TestWorkflowContext> step, Predicate<TestWorkflowContext> canExecute)
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Registers the provided action as a step in the workflow on the specified thread in which to execute. Will
            /// only execute the step if execution condition evaluates to 'true' when the step is next in the workflow.
            /// </summary>
            /// <param name="step">The step.</param>
            /// <param name="thread">The thread.</param>
            /// <param name="canExecute">Execution condition.</param>
            /// <param name="stepName">Name of the step.</param>
            public void RegisterStep(Action<TestWorkflowContext> step, ThreadType thread, Predicate<TestWorkflowContext> canExecute, string stepName)
            {
                throw new NotImplementedException();
            }

            #endregion
        }

        internal class TestWorkflowContext : IWorkflowContext
        {
            
        }
    }
}
